/**
 * Model implementation
 */

#include "Model.h"

/////////////////////////////////////////////////

void Model::translate(const Vec3& v)
{
	std::vector<PartPtr>::iterator iter;
	std::vector<Vec3>::iterator vIter;
	for (iter=parts.begin(); iter!=parts.end(); ++iter) {
		for (vIter=(*iter)->verts.begin(); vIter!=(*iter)->verts.end(); ++vIter) {
			(*vIter) += v;
		}
	}
}

/////////////////////////////////////////////////

void Model::scale(const float s)
{
	std::vector<PartPtr>::iterator iter;
	std::vector<Vec3>::iterator vIter;
	for (iter=parts.begin(); iter!=parts.end(); ++iter) {
		for (vIter=(*iter)->verts.begin(); vIter!=(*iter)->verts.end(); ++vIter) {
			(*vIter) *= s;
		}
	}
}
/////////////////////////////////////////////////

void Model::setBoundingCoords()
{
    Vec3 maxCoord;
    Vec3 minCoord;
    _hasBoundingBox = true;
    int first_loop = 1;
	std::vector<PartPtr>::iterator iter;
	std::vector<Vec3>::iterator vIter;
	for (iter=parts.begin(); iter!=parts.end(); ++iter) {
		for (vIter=(*iter)->verts.begin(); vIter!=(*iter)->verts.end(); ++vIter) {
            if (first_loop) {
                first_loop = 0;
                maxCoord = (*vIter);
                minCoord = (*vIter);
            } else {
                for (int i=0; i<3; i++) {
                    maxCoord[i] = 
                        ((*vIter)[i] > maxCoord[i]) ? (*vIter)[i] : maxCoord[i];
                    minCoord[i] = 
                        ((*vIter)[i] < minCoord[i]) ? (*vIter)[i] : minCoord[i];
                }
            }
		}
	}
    bbCorners[0] = Vec4(maxCoord[0], maxCoord[1], maxCoord[2], 1.0);
    bbCorners[1] = Vec4(minCoord[0], maxCoord[1], maxCoord[2], 1.0);
    bbCorners[2] = Vec4(maxCoord[0], minCoord[1], maxCoord[2], 1.0);
    bbCorners[3] = Vec4(minCoord[0], minCoord[1], maxCoord[2], 1.0);
    bbCorners[4] = Vec4(maxCoord[0], minCoord[1], minCoord[2], 1.0);
    bbCorners[5] = Vec4(minCoord[0], minCoord[1], minCoord[2], 1.0);
    bbCorners[6] = Vec4(maxCoord[0], maxCoord[1], minCoord[2], 1.0);
    bbCorners[7] = Vec4(minCoord[0], maxCoord[1], minCoord[2], 1.0);
}
/////////////////////////////////////////////////

void Model::skipLine(std::istream& is)
{
    char next;
    is >> std::noskipws;
    while( (is >> next) && ('\n' != next) );
}

/////////////////////////////////////////////////

void Model::sendToCard()
{
	std::vector<PartPtr>::iterator iter;
	std::cerr << "Sending " << _name << " to card." << std::endl;
	for (iter=parts.begin(); iter!=parts.end(); ++iter) {
		assert((*iter)->vbo == 0);
        (*iter)->vbo = 1;
		int norm_index=(*iter)->tris.size()*9;

		unsigned int *element_data = 
            new unsigned int[(*iter)->tris.size() * 3];
		float *vertex_data = new float[(*iter)->tris.size() * 9 * 2];
		float *normal_data = new float[(*iter)->tris.size() * 9];
        float *indexed_data = new float[(*iter)->norms.size() * 3 * 2];

		std::cerr << "\t" << (*iter)->tris.size() << std::endl;

		for (int i=0; i<(int)(*iter)->tris.size(); ++i)
        {
            Triangle t = (*iter)->tris[i];
            for (int j=0; j<3; ++j)
            {
                element_data[i*3 + j] = t.n[j];
                for (int k=0; k<3; ++k)
                {
                    vertex_data[i*18 + j*6 + k] = (*iter)->verts[t.v[j]][k];
                    vertex_data[i*18 + j*6 + k + 3] = (*iter)->norms[t.n[j]][k];
                    indexed_data[t.n[j]*6 + k] = (*iter)->verts[t.v[j]][k];
                    indexed_data[t.n[j]*6 + k + 3] = (*iter)->norms[t.n[j]][k];
                }
            }
        }

        ///*
		glGenBuffers(1, &(*iter)->vbo);
        glBindBuffer(GL_ARRAY_BUFFER, (*iter)->vbo);
		glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*((*iter)->tris.size() * 9 *2), 
                     vertex_data, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        //*/


        /*
		glGenBuffers(1, &(*iter)->array_buffer_name);
        glBindBuffer(GL_ARRAY_BUFFER, (*iter)->array_buffer_name);
		glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*(*iter)->norms.size()*3*2, 
                     indexed_data, GL_STATIC_DRAW);

		glGenBuffers(1, &(*iter)->element_buffer_name);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*iter)->element_buffer_name);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
                     sizeof(unsigned int)*(*iter)->tris.size()*3, 
                     element_data, GL_STATIC_DRAW);
        */


		delete[] indexed_data;
		delete[] element_data;
		delete[] vertex_data;

	}

	std::cerr << "Done sending buffer " << _name << " to card." << std::endl;
	
}

/////////////////////////////////////////////////

void Model::loadOBJ(const std::string& objfile)
{
    PartPtr part(new Part());
    std::string token;
    float x, y, z;
    int fv[3];
    //int ft[3];
    int fn[3];
    char next;
    Vec3 vec;


    std::ifstream obj;
    obj.open(objfile.c_str());
    
    if (!obj.good())
    {
        std::cout << "bad objfile" << std::endl;
        return;
    }
    while( !obj.eof() )
    {
        while( obj >> std::skipws >> next )
        {
            obj.putback(next);
            if ('#' == next)
                skipLine(obj);
            else
                break;
        }

        obj >> token;

        if (token == "g")
        {
            skipLine(obj);
        }
        else if (token == "v")
        {
            obj >> x >> y >> z;
            part->verts.push_back(Vec3( x, y, z));
        }
        else if (token == "vn")
        {
            obj >> x >> y >> z;
            part->norms.push_back(Vec3( x, y, z));
        }
        else if (token == "vt")
        {
            skipLine(obj);
        }
        else if (token == "mtllib")
        {
            skipLine(obj);
        }
        else if (token == "usemtl")
        {
            skipLine(obj);
        }
        else if (token == "f")
        {
            char c;
            for (int i=0; i<3; i++)
            {
                obj >> fv[i];
                c = obj.get();
                c = obj.get();
                //obj.ignore(1, '/');
                //obj >> ft[i];
                //obj.ignore(1, '/');
                obj >> fn[i];
            }
            part->tris.push_back(Triangle( fv[0]-1, fv[1]-1, fv[2]-1, 
                                           fn[0]-1, fn[1]-1, fn[2]-1 ));

        }

    }
    std::cout << objfile << std::endl;
    std::cout << "  Verts: " << part->verts.size() << std::endl;
    std::cout << "  Norms: " << part->norms.size() << std::endl;
    std::cout << "  Tris: " << part->tris.size() << std::endl;

    parts.push_back(part);

}





        
        
        


